package com.robot.agent.controller;

import com.alibaba.fastjson.JSON;
import com.robot.agent.client.MerchantClient;
import com.robot.agent.client.SmsClient;
import com.robot.agent.pojo.Agent;
import com.robot.agent.service.AgentService;
import com.robot.agent.util.SendMessageUtil;
import entity.*;
import io.jsonwebtoken.Claims;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.data.domain.Page;
import org.springframework.security.crypto.bcrypt.BCryptPasswordEncoder;
import org.springframework.transaction.annotation.Transactional;
import org.springframework.web.bind.annotation.*;
import util.CheckUtil;
import util.JwtUtil;
import util.UpdateUtil;

import javax.servlet.http.HttpServletRequest;
import java.time.LocalDateTime;
import java.util.HashMap;
import java.util.Map;

/**
 * agent控制器层
 *
 * @author wuyunbin
 */
@RestController
@CrossOrigin
@RequestMapping("/agent")
public class AgentController {
    private final Logger logger = LoggerFactory.getLogger(this.getClass());

    @Autowired
    private AgentService agentService;


    @Autowired
    private MerchantClient merchantClient;

    @Autowired
    private BCryptPasswordEncoder encoder;
    @Autowired
    private HttpServletRequest request;

    @Autowired
    private CheckUtil checkUtil;
    @Autowired
    private JwtUtil jwtUtil;
    @Autowired
    private SendMessageUtil sendMessageUtil;

    @Autowired
    private SmsClient smsClient;

    /**
     * 消息推送内容长度
     */
    @Value("${sys.messagePushContentLength}")
    private int messagePushContentLength;

    /**
     * 消息推送type 0-短信 1-站内信 2-邮件 3-微信
     */
    private int phoneMessagePush = 0;
    private int mailMessagePush = 1;
    private int emailMessagePush = 2;
    private int weChatMessagePush = 3;

    /**
     * agent表status状态 0-禁用 1-启用
     */
    private String agentStatusEnable = "1";
    /**
     * agent表agent_type 代理商类型 0-私人 1-公司
     */
    private String agentAgentTypeZero = "0";
    private String agentAgentTypeOne = "1";
    /**
     * agent表account_type 账户类型 0-对私 1-对公
     */
    private String agentAccountTypeZero = "0";
    private String agentAccountTypeOne = "1";

    /**
     * store表status状态 0-禁用 1-启用
     */
    private String storeStatusEnable = "1";


    /**
     * 代理商个人中心
     *
     * @return
     */
    @RequestMapping(value = "personalCenter", method = RequestMethod.GET)
    public Result personalCenter() {
        Claims claims = (Claims) request.getAttribute("robot_agent");
        if (claims == null) {
            return new Result(StatusCode.ERROR_TOKEN_EXPIRED);
        }
        logger.info("claims.getId()=" + claims.getId());
        Agent agentInDb = agentService.findById(claims.getId());
        logger.info("agentInDb=" + agentInDb);
        //前端调用findByToken接口检查过了,所以这里不再对代理商是否存在和状态进行判断

        return new Result(StatusCode.SUCCESS_QUERY, agentInDb);
    }

    /**
     * 代理商分页+多条件查询
     *
     * @param searchMap 查询条件封装
     * @param page      页码
     * @param size      页大小
     * @return 分页结果
     */
    @RequestMapping(value = "/search/{page}/{size}", method = RequestMethod.POST)
    public Result findSearch(@RequestBody Map searchMap, @PathVariable int page, @PathVariable int size) {
        logger.info("searchMap=" + searchMap);
        Claims claims = (Claims) request.getAttribute("robot_agent");
        if (claims == null) {
            return new Result(StatusCode.ERROR_TOKEN_EXPIRED);
        }
        logger.info("claims.getId()=" + claims.getId());
        //前端调用findByToken接口检查过了,所以这里不再对代理商是否存在和状态进行判断

        Page<Agent> pageList = agentService.findSearch(searchMap, page, size);
        return new Result(StatusCode.SUCCESS_QUERY, new PageResult<Agent>(pageList.getTotalElements(), pageList.getContent()));
    }

    /**
     * 代理商根据条件查询
     *
     * @param searchMap
     * @return
     */
    @RequestMapping(value = "/search", method = RequestMethod.POST)
    public Result findSearch(@RequestBody Map searchMap) {
        return new Result(StatusCode.SUCCESS_QUERY, agentService.findSearch(searchMap));
    }

    /**
     * 代理商短信验证码登录
     *
     * @param agent     agent
     * @param checkCode 验证码
     * @return Result
     */
    @RequestMapping(value = "/login/phone/{checkCode}", method = RequestMethod.POST)
    @Transactional(rollbackFor = Exception.class)
    public Result loginByPhoneSms(@RequestBody Agent agent, @PathVariable String checkCode) {
        String phone = agent.getPhone();
        if (!checkUtil.checkPhone(phone)) {
            return new Result(StatusCode.ERROR_INVALID_PHONE);
        }
        checkCode = checkCode.trim();
        if ("".equals(checkCode)) {
            return new Result(StatusCode.ERROR_VERIFICATION_CODE_REQUIRED);
        }
        //验证码是不是过期
        Sms sms = new Sms("agent", phone, "login");
        if (!smsClient.isCheckCodeExpire(sms)) {
            return new Result(StatusCode.ERROR_VERIFICATION_CODE_EXPIRED);
        }
        //验证码是否正确
        if (!smsClient.isCorrectCheckCode(sms, checkCode)) {
            return new Result(StatusCode.ERROR_VERIFICATION_CODE);
        }

        //根据手机号取出数据库中的数据
        Agent agentInDb = agentService.findAgentByPhone(phone);
        if (agentInDb == null) {
            return new Result(StatusCode.ERROR_AGENT_DOES_NOTE_EXIST);
        }
        HashMap<String, String> map = new HashMap<>(2);
        map.put("token", jwtUtil.createJwt(agentInDb.getId(), agent.getPhone(), "agent"));
        map.put("role", "agent");
        //删除redis里面的验证码
        smsClient.deleteCheckCode(sms);
        return new Result(StatusCode.SUCCESS_LOGIN, map);
    }

    /**
     * 代理商账户密码登录
     *
     * @param agent
     * @return Result
     */
    @RequestMapping(value = "/login", method = {RequestMethod.POST})
    @Transactional(rollbackFor = Exception.class)
    public Result loginByPassword(@RequestBody Agent agent) {
        String phone = agent.getPhone();
        if (!checkUtil.checkPhone(phone)) {
            return new Result(StatusCode.ERROR_INVALID_PHONE);
        }
        Agent agentInDb = agentService.findAgentByPhone(phone);
        //判断admin是否存在
        if (agentInDb == null) {
            return new Result(StatusCode.ERROR_AGENT_DOES_NOTE_EXIST);
        }
        //判断密码
        if (agent.getPassword() == null || "".equals(agent.getPassword())) {
            return new Result(StatusCode.ERROR_PASSWORD_REQUIRED);
        }
        if (!encoder.matches(agent.getPassword(), agentInDb.getPassword())) {
            return new Result(StatusCode.ERROR_PASSWORD_WRONG);
        }

        HashMap<String, String> map = new HashMap<>(2);
        map.put("token", jwtUtil.createJwt(agentInDb.getId(), agent.getPhone(), "agent"));
        map.put("role", "agent");
        //删除redis里面的验证码
        return new Result(StatusCode.SUCCESS_LOGIN, map);
    }

    /**
     * 代理商更换密码
     *
     * @param checkCode 短信验证码
     * @param agent
     * @return Result
     */
    @RequestMapping(value = "/updatePassword/{checkCode}", method = RequestMethod.PUT)
    @Transactional(rollbackFor = Exception.class)
    public Result updatePassword(@PathVariable String checkCode, @RequestBody Agent agent) {
        Claims claims = (Claims) request.getAttribute("robot_agent");
        if (claims == null) {
            return new Result(StatusCode.ERROR_TOKEN_EXPIRED);
        }

        String phone = agent.getPhone();
        if (phone == null || "".equals(phone)) {
            return new Result(StatusCode.ERROR_PHONE_REQUIRED);
        }
        if (!checkUtil.checkPhone(phone)) {
            return new Result(StatusCode.ERROR_INVALID_PHONE);
        }
        String password = agent.getPassword();
        if (password == null || "".equals(password)) {
            return new Result(StatusCode.ERROR_PASSWORD_REQUIRED);
        }

        Agent agentInDb = agentService.findById(claims.getId());
        if (agentInDb == null || !agentInDb.getPhone().equals(phone)) {
            return new Result(StatusCode.ERROR_AGENT_DOES_NOTE_EXIST);
        }
        if (!agentStatusEnable.equals(agentInDb.getStatus())) {
            return new Result(StatusCode.ERROR_USER_INVALID);
        }

        Sms sms = new Sms("agent", phone, "updatePassword");
        //验证码是不是过期
        if (!smsClient.isCheckCodeExpire(sms)) {
            return new Result(StatusCode.ERROR_VERIFICATION_CODE_EXPIRED);
        }
        //验证码是否正确
        if (!smsClient.isCorrectCheckCode(sms, checkCode)) {
            return new Result(StatusCode.ERROR_VERIFICATION_CODE);
        }

        agentInDb.setPassword(encoder.encode(agent.getPassword()));
        agentService.update(agentInDb);
        return new Result(StatusCode.SUCCESS_UPDATED);
    }

    /**
     * 代理商找回密码
     *
     * @param checkCode
     * @param agent
     * @return
     */
    @RequestMapping(value = "/findPassword/{checkCode}", method = RequestMethod.PUT)
    @Transactional(rollbackFor = Exception.class)
    public Result findPassword(@PathVariable String checkCode, @RequestBody Agent agent) {
        String phone = agent.getPhone();
        if (phone == null || "".equals(phone)) {
            return new Result(StatusCode.ERROR_PHONE_REQUIRED);
        }
        if (!checkUtil.checkPhone(phone)) {
            return new Result(StatusCode.ERROR_INVALID_PHONE);
        }
        String password = agent.getPassword();
        if (password == null || "".equals(password)) {
            return new Result(StatusCode.ERROR_PASSWORD_REQUIRED);
        }

        Agent agentInDb = agentService.findAgentByPhone(phone);
        if (agentInDb == null) {
            return new Result(StatusCode.ERROR_AGENT_DOES_NOTE_EXIST);
        }
        if (!agentStatusEnable.equals(agentInDb.getStatus())) {
            return new Result(StatusCode.ERROR_USER_INVALID);
        }

        Sms sms = new Sms("agent", phone, "findPassword");

        //验证码是不是过期
        if (!smsClient.isCheckCodeExpire(sms)) {
            return new Result(StatusCode.ERROR_VERIFICATION_CODE_EXPIRED);
        }
        //验证码是否正确
        if (!smsClient.isCorrectCheckCode(sms, checkCode)) {
            return new Result(StatusCode.ERROR_VERIFICATION_CODE);
        }

        agentInDb.setPassword(encoder.encode(agent.getPassword()));
        agentService.update(agentInDb);
        return new Result(StatusCode.SUCCESS_UPDATED);
    }

    /**
     * 代理商修改资料
     *
     * @param agent
     */
    @RequestMapping(value = "", method = RequestMethod.PUT)
    @Transactional(rollbackFor = Exception.class)
    public Result updateAgent(@RequestBody Agent agent) {
        Claims claims = (Claims) request.getAttribute("robot_agent");
        if (claims == null) {
            return new Result(StatusCode.ERROR_TOKEN_EXPIRED);
        }
        logger.info("claims.getId()=" + claims.getId());
        Agent agentInDb = agentService.findById(claims.getId());
        logger.info("agentInDb=" + agentInDb);
        if (agentInDb == null) {
            return new Result(StatusCode.ERROR_AGENT_DOES_NOTE_EXIST);
        }
        if (!agentStatusEnable.equals(agentInDb.getStatus())) {
            return new Result(StatusCode.ERROR_USER_INVALID);
        }

        if (agent.getPhone() != null || !"".equals(agent.getPhone())) {
            if (!checkUtil.checkPhone(agent.getPhone())) {
                return new Result(StatusCode.ERROR_INVALID_PHONE);
            }
        }
        if (agent.getEmail() != null || !"".equals(agent.getEmail())) {
            if (checkUtil.checkEmail(agent.getEmail())) {
                return new Result(StatusCode.ERROR_INVALID_EMAIL);
            }
        }
        if (agent.getAgentType() != null || !"".equals(agent.getAgentType())) {
            if (!agentAgentTypeOne.equals(agent.getAgentType()) && !agentAgentTypeZero.equals(agent.getAgentType())) {
                return new Result(StatusCode.ERROR_AGENT_AGENT_TYPE_INVALID);
            }
        }
        if (agent.getAccountType() != null || !"".equals(agent.getAccountType())) {
            if (!agentAccountTypeOne.equals(agent.getAccountType()) && !agentAccountTypeZero.equals(agent.getAccountType())) {
                return new Result(StatusCode.ERROR_AGENT_ACCOUNT_TYPE_INVALID);
            }
        }
        //代理商修改资料
        updatePojo(agent, agentInDb);
        return new Result(StatusCode.SUCCESS_UPDATED);
    }

    /**
     * 商家列表
     *
     * @param page
     * @param size
     * @return
     */
    @GetMapping("stores/{page}/{size}")
    public Result findStores(@PathVariable int page, @PathVariable int size) {
        Claims claims = (Claims) request.getAttribute("robot_agent");
        if (claims == null) {
            return new Result(StatusCode.ERROR_TOKEN_EXPIRED);
        }
        logger.info("claims.getId()=" + claims.getId());
        //前端调用findByToken接口检查过了,所以这里不再对代理商是否存在和状态进行判断

        return new Result(StatusCode.SUCCESS_QUERY, JSON.parseObject(merchantClient.thirdFindStoresByAgentIdOrderByCreatedAtDesc(claims.getId(), page, size)));
    }

    /**
     * 商家列表-条件搜索
     *
     * @param page
     * @param size
     * @return
     */
    @RequestMapping(value = "storesBySearch/{page}/{size}", method = RequestMethod.POST)
    public Result findStoresBySearch(@RequestBody Map searchMap, @PathVariable int page, @PathVariable int size) {
        Claims claims = (Claims) request.getAttribute("robot_agent");
        if (claims == null) {
            return new Result(StatusCode.ERROR_TOKEN_EXPIRED);
        }
        Agent agentInDb = agentService.findById(claims.getId());
        logger.info("agentInDb=" + agentInDb);
        //前端调用findByToken接口检查过了,所以这里不再对代理商是否存在和状态进行判断


        searchMap.put("agentId", agentInDb.getId());
        logger.info("searchMap=" + searchMap);
        return new Result(StatusCode.SUCCESS_QUERY, JSON.parseObject(merchantClient.thirdFindStores(searchMap, page, size)));
    }


    /**
     * 消息推送
     *
     * @param map
     * @return
     */
    @PostMapping("messagePush")
    public Result sendSms(@RequestBody Map map) {
        Map<String, Object> resultMap = sendMessageUtil.sendMessage(map);
        String flag = "flag";
        String code = "code";
        if (!(boolean) resultMap.get(flag)) {
            return new Result((Status) resultMap.get(code));
        }
        return new Result(StatusCode.SUCCESS_SEND);
    }


    /**
     * 检验token
     *
     * @return
     */
    @GetMapping("checkToken")
    public Result checkToken() {
        Claims claims = (Claims) request.getAttribute("robot_agent");
        if (claims == null) {
            logger.info("claims is null");
            return new Result(StatusCode.ERROR_TOKEN_EXPIRED);
        }
        Agent agentInDb = agentService.findById(claims.getId());
        logger.info("id=" + claims.getId());
        if (agentInDb == null) {
            logger.info("agent is not in Db");
            return new Result(StatusCode.ERROR_USER_DOES_NOTE_EXIST);
        }
        if (!agentStatusEnable.equals(agentInDb.getStatus())) {
            logger.info("member status invalid");
            return new Result(StatusCode.ERROR_USER_INVALID);
        }
        return new Result(StatusCode.SUCCESS_VERIFY);
    }

    /**
     * 代理商信息
     *
     * @return
     */
    @RequestMapping(value = "/findByToken", method = RequestMethod.POST)
    public Result findByToken() {
        Claims claims = (Claims) request.getAttribute("robot_agent");
        if (claims == null) {
            return new Result(StatusCode.ERROR_TOKEN_EXPIRED);
        }
        Agent memberInDb = agentService.findById(claims.getId());
        if (memberInDb == null) {
            return new Result(StatusCode.ERROR_USER_DOES_NOTE_EXIST);
        }
        if (!agentStatusEnable.equals(memberInDb.getStatus())) {
            return new Result(StatusCode.ERROR_USER_INVALID);
        }
        return new Result(StatusCode.SUCCESS_QUERY, memberInDb);
    }


    /**
     * update时更新实体类
     *
     * @param agent
     * @param agentInDb
     */
    public void updatePojo(Agent agent, Agent agentInDb) {
        agent.setId(agentInDb.getId());
        agent.setStatus(agentInDb.getStatus());
        agent.setRealNameStatus(agentInDb.getRealNameStatus());
        agent.setPassword(agentInDb.getPassword());
        agent.setCreatedAt(agentInDb.getCreatedAt());
        UpdateUtil.copyNonNullProperties(agent, agentInDb);
        agentInDb.setUpdatedAt(LocalDateTime.now());
        agentService.update(agentInDb);
    }

}
